有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java MethodHandle与通用非类返回筛选器?

我正试图通过使用^{}来建立一个MethodHandle,它有一个通用的返回值过滤器

我的问题是我不知道(也不关心)返回类型,所以我希望将Object myfilter(Object obj)作为MethodHandle来过滤返回对象。但是,在MethodHandles.filterReturnValue()调用中显然不允许这样做

以下是我希望能起作用的东西(但没有)

package invoke;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Method;
import java.util.Arrays;

public class MethodHandleReturnExample
{
    public static void main(String[] args) throws Throwable
    {
        MethodHandles.Lookup lookup = MethodHandles.lookup();
        Testcase test = new Testcase();
        MethodHandle onCount = findMethodByName(lookup, test, "onCount");
        MethodHandle onNada = findMethodByName(lookup, test, "onNada");
        MethodHandle onText = findMethodByName(lookup, test, "onText");

        onNada.invoke("hello");
        onText.invoke("world");
        onCount.invoke();
        onCount.invoke();
        onCount.invoke();
    }

    private static MethodHandle findMethodByName(MethodHandles.Lookup lookup, Object obj, String methodName) throws IllegalAccessException, NoSuchMethodException
    {
        Method method = Arrays.stream(obj.getClass().getDeclaredMethods())
                .filter(m -> m.getName().equalsIgnoreCase(methodName))
                .findFirst().get();
        MethodHandle handle = lookup.unreflect(method);
        handle = handle.bindTo(obj);

        if (handle.type().returnType() != Void.TYPE)
        {
            MethodHandle returnFilter = lookup.findVirtual(Util.class, "filter", MethodType.methodType(Object.class,Object.class));
            returnFilter = returnFilter.bindTo(new Util());
            handle = MethodHandles.filterReturnValue(handle, returnFilter);
        }
        return handle;
    }

    public static class Testcase
    {
        int count = 0;

        public int onCount()
        {
            int ret = ++count;
            System.out.printf("onCount() : %d%n", ret);
            return ret;
        }

        public void onNada(String msg)
        {
            System.out.printf("onNada(%s)%n", msg);
        }

        public String onText(String msg)
        {
            System.out.printf("onText(%s)%n", msg);
            return "[text:" + msg + "]";
        }
    }

    public static class Util
    {
        public Object filter(Object obj)
        {
            System.out.printf("# filter((%s) %s)%n", obj.getClass().getName(), obj);
            return obj;
        }
    }
}

看来MethodHandles.filterReturnValue()不适合这个目的

当时我希望我可以制作一个MethodHandle来调用另一个MethodHandle,但这开始变得复杂起来

例如:

public Object filter(MethodHandle handle, Object ... args)
{
    Object ret = handle.invoke(args);
    System.out.printf("# filter((%s) %s)%n", ret.getClass().getName(), ret);
    return ret;
}

我试着去想一下^{}甚至^{},但从javadoc和网上找到的少量示例来看,它们很难理解


共 (1) 个答案

  1. # 1 楼答案

    filterReturnValue将调用target句柄,如果它正在使用invokeExact,那么返回类型必须完全匹配

    因此,您必须将返回类型调整为Object。最简单的方法是使用asType(这也会自动将int框起来):

    if (handle.type().returnType() != Void.TYPE) {
        handle = handle.asType(handle.type().changeReturnType(Object.class)); // < -
    
        MethodHandle returnFilter = lookup.findVirtual(Util.class, "filter",
                MethodType.methodType(Object.class, Object.class));
        returnFilter = returnFilter.bindTo(new Util());
        handle = MethodHandles.filterReturnValue(handle, returnFilter);
    }